package com.dream.libxrec.player;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.SystemClock;
import android.util.Log;

import com.dream.libsoundtouch.SoundTouch;

public class PCMPlayer {

    private AudioTrack mAudioTrack;
    private volatile boolean isStop = false;
    private SoundTouch mSoundTouch = new SoundTouch();//变速处理工具
    private float mPlayRate = 1.0f;//播放速率
    private float mPlayTempo = 1.0f;//播放节奏
    private short[] mSwapBuffer = null;
    private boolean isMute = false;
    private final int mSampleRate;
    private int mBitSample = 16;
    private final int mChannelNum;
    private short[] mOutputBuffer = null;

    /**
     *
     * @param bufferSize 缓存区大小，单次写入（播放）数据量不能大于该值，如2048
     * @param sampleRate 采样率,如8000、16000、44100 单位为kHz
     * @param channel 通道数 1或2
     * @param bitSample 位数 如：AudioFormat.ENCODING_PCM_16BIT
     *                  由于SoundTouch只支持16位,如果用其他位数，那么不要用快进慢放功能了
     */
    public PCMPlayer(int bufferSize,int sampleRate, int channel,int bitSample){
        this.mChannelNum = channel;
        this.mSampleRate = sampleRate;
        switch (bitSample){
            case AudioFormat.ENCODING_PCM_16BIT:
                mSoundTouch.setSampleRate(sampleRate);
                mSoundTouch.setChannels(channel);
                this.mBitSample = 16;
                break;
            case AudioFormat.ENCODING_PCM_8BIT:
                this.mBitSample = 8;
                break;
            case AudioFormat.ENCODING_PCM_32BIT:
                this.mBitSample = 32;
                break;
        }

        int streamType = AudioManager.STREAM_MUSIC;//音乐类型，扬声器播放

        int channelConfig = channel == 1?AudioFormat.CHANNEL_OUT_MONO:AudioFormat.CHANNEL_OUT_STEREO;//录音时采用单声道输入，故而播放时也采用单声道播放

        int mode = AudioTrack.MODE_STREAM;//流模式

        int minBufferSize = AudioTrack.getMinBufferSize(sampleRate
                ,channelConfig,bitSample);

        mAudioTrack = new AudioTrack(streamType,sampleRate,channelConfig
                ,bitSample,Math.max(bufferSize,minBufferSize),mode);
        mAudioTrack.play();
    }

    public void setRate(float rate){
        this.mPlayRate = rate;
        if (mSoundTouch != null){
            mSoundTouch.setRateChange(rate);
        }
    }

    public void setTempoChange(float rate){
        this.mPlayTempo = rate;
        if (mSoundTouch != null){
            mSoundTouch.setTempoChange(rate);
        }
    }

    public synchronized void play(byte[] data,int len){
        if (isStop){
            return;
        }

        if (isMute){
            //静音模式下，直接按照音频的时长休眠即可
            if (mPlayRate != 1){
                SystemClock.sleep(calculateDuration(len,mSampleRate,
                        mChannelNum,mBitSample,mPlayRate));
            }else{
                SystemClock.sleep(calculateDuration(len,mSampleRate,
                        mChannelNum,mBitSample,mPlayTempo));
            }
        }else if (mSoundTouch == null||(mPlayRate == 1 && mPlayTempo == 1)){
            int res = mAudioTrack.write(data,0,len);
            switch (res){
                case AudioTrack.ERROR_BAD_VALUE:
                case AudioTrack.ERROR_INVALID_OPERATION:
                case AudioTrack.ERROR_DEAD_OBJECT:
                    //TODO:播放失败
                    Log.i("MAudioPlayer","播放失败:"+res);
                default:
                    break;
            }
        }else{
            short[] shortArray = toShortArray(data,len);
            playSoundTouch(shortArray,shortArray.length);
        }
    }

    public void play(short[] data,int len){
        if (isStop){
            return;
        }
        if (isMute){
            //静音模式下，直接按照音频的时长休眠即可
            if (mPlayRate != 1){
                SystemClock.sleep(calculateDuration(len*2,mSampleRate,
                        mChannelNum,mBitSample,mPlayRate));
            }else{
                SystemClock.sleep(calculateDuration(len*2,mSampleRate,
                        mChannelNum,mBitSample,mPlayTempo));
            }
        }else if (mSoundTouch == null||(mPlayRate == 1 && mPlayTempo == 1)) {
            int res = mAudioTrack.write(data, 0, len);
            switch (res) {
                case AudioTrack.ERROR_BAD_VALUE:
                case AudioTrack.ERROR_INVALID_OPERATION:
                case AudioTrack.ERROR_DEAD_OBJECT:
                    //TODO:播放失败
                    Log.i("MAudioPlayer", "播放失败:"+res);
                default:
                    break;
            }
        }else{
            playSoundTouch(data,len);
        }
    }

    private void playSoundTouch(short[] data,int len){
        mSoundTouch.putSamples(data,len);

        //如果是快进的话，如果是tempo的话，二倍速并不一定输出的数据量并不一定是原来的一半，可能更多
        int bufferSize =
                Math.max(len,
                        Math.round(len/((mPlayTempo == 1)?
                mPlayRate:mPlayTempo)));

        if (mOutputBuffer == null || mOutputBuffer.length < bufferSize){
            mOutputBuffer = new short[bufferSize];
        }

        int size = mSoundTouch.receiveSamples(mOutputBuffer,
                mOutputBuffer.length);
        toPlay(mOutputBuffer,size);
    }

    private short[] toShortArray(byte[] src,int size) {

        int count = size/2;
        if (mSwapBuffer == null || mSwapBuffer.length < count){
            mSwapBuffer = new short[count];
        }

        for (int i = 0; i < count; i++) {
            mSwapBuffer[i] =
                    (short) (src[i * 2+1] << 8 | src[2 * i] & 0xff);
        }
        return mSwapBuffer;
    }

    private void toPlay(short[] data,int len){
        if (isStop){
            return;
        }

        int res = mAudioTrack.write(data,0,len);
        switch (res){
            case AudioTrack.ERROR_BAD_VALUE:
            case AudioTrack.ERROR_INVALID_OPERATION:
            case AudioTrack.ERROR_DEAD_OBJECT:
                //TODO:播放失败
                Log.i("MAudioPlayer","播放失败");
            default:
                break;
        }
    }

    public synchronized void stop(){
        isStop = true;

        if (mAudioTrack != null){
            mAudioTrack.stop();
            mAudioTrack.release();
            mAudioTrack = null;
        }

        if (mSoundTouch != null){
            mSoundTouch.clear();
            mSoundTouch = null;
        }

        mSwapBuffer = null;
    }

    public void setMute(boolean isMute){
        this.isMute = isMute;
    }

    public boolean isMute(){
        return isMute;
    }

    /**
     * 计算音频播放时长
     * @param dataLen 音频数据字节长度
     * @param sampleRate 采样率
     * @param channelCount 通道数
     * @param bitDepth 每个采样的位深，通常为16
     * @param playRate 播放倍率 1为正常，2为2倍数速，0.5为0.5倍速
     * @return
     */
    public long calculateDuration(int dataLen, int sampleRate,
                                  int channelCount, int bitDepth,
                                  float playRate) {
        int bytesPerSample = bitDepth / 8;
        int totalSamples = dataLen / bytesPerSample / channelCount;
        double durationSeconds =
                totalSamples / (double) sampleRate/playRate;
        return (long) (durationSeconds * 1000);
    }
}